package com.mes.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import com.mes.biz.domain.*;
import com.mes.biz.domain.vo.ConvertRatioNumberUnit;
import com.mes.biz.domain.vo.PurchaseProductVo;
import com.mes.biz.mapper.BizPurchaseMapper;
import com.mes.biz.mapper.BizSupplierMapper;
import com.mes.biz.mapper.BizSupplierPayableMapper;
import com.mes.biz.service.*;
import com.mes.common.constant.BizConstants;
import com.mes.common.core.domain.BaseEntity;
import com.mes.common.core.page.PageDomain;
import com.mes.common.core.service.BaseServiceImpl;
import com.mes.common.exception.BizException;
import com.mes.common.utils.DateUtils;
import com.mes.common.utils.SecurityUtils;
import com.mes.common.utils.StringUtils;
import com.mes.common.utils.sql.SqlUtil;
import com.mes.system.strategy.AutoCodeUtil;
import org.apache.commons.compress.utils.Sets;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 采购单表头Service业务层处理
 * @author wy
 * @email wy
 * @date 2023-05-19
 */
@Service
@Transactional(readOnly = true)
public class BizPurchaseServiceImpl extends BaseServiceImpl<BizPurchaseMapper, BizPurchase> implements BizPurchaseService {

    @Resource
    private AutoCodeUtil autoCodeUtil;
    @Resource
    private BizPurchaseMapper bizPurchaseMapper;
    @Resource
    private BizPurchaseDetailService bizPurchaseDetailService;
    @Resource
    private BizSupplierMapper bizSupplierMapper;
    @Resource
    private BizSupplierPayableMapper bizSupplierPayableMapper;
    @Resource
    private BizProductInventoryService bizProductInventoryService;
    @Resource
    private BizProductInventoryBookService bizProductInventoryBookService;
    @Resource
    private BizProductService bizProductService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createPurchase(BizPurchase bizPurchase) {
        String code = autoCodeUtil.genSerialCode("PURCHASE_CODE","");
        bizPurchase.setPurchaseCode(code);
        String tenantId = SecurityUtils.getTenantId();
        bizPurchase.setTenantId(tenantId);
        bizPurchase.setStatus(1);
        BigDecimal purchaseAmount = BigDecimal.ZERO;
        if(bizPurchase.getDetailList().size() > 0) {
            purchaseAmount = bizPurchase.getDetailList().stream().map(BizPurchaseDetail::getTotalAmount).reduce(BigDecimal.ZERO,BigDecimal::add);
        }
        bizPurchase.setPurchaseAmount(purchaseAmount);
        bizPurchase.setPayAmount(BigDecimal.ZERO);
        boolean res = save(bizPurchase);
        if(res) {
            BigDecimal amount = BigDecimal.ZERO;
            for (int i = 0; i < bizPurchase.getDetailList().size(); i++) {
                BizPurchaseDetail purchaseDetail = new BizPurchaseDetail();
                purchaseDetail.setSupplierCode(bizPurchase.getSupplierCode());
                purchaseDetail.setProductCode(bizPurchase.getDetailList().get(i).getProductCode());
                purchaseDetail.setTotalAmount(bizPurchase.getDetailList().get(i).getTotalAmount());
                purchaseDetail.setUnit(bizPurchase.getDetailList().get(i).getUnit());
                purchaseDetail.setSpaceId(bizPurchase.getDetailList().get(i).getSpaceId());
                purchaseDetail.setUnitPrice(bizPurchase.getDetailList().get(i).getUnitPrice());
                purchaseDetail.setProductNumber(bizPurchase.getDetailList().get(i).getProductNumber());
                purchaseDetail.setPurchaseCode(bizPurchase.getPurchaseCode());
                purchaseDetail.setTenantId(tenantId);
                purchaseDetail.setRemark(bizPurchase.getDetailList().get(i).getRemark());
                purchaseDetail.setBalance(bizPurchase.getDetailList().get(i).getUnitPrice());
                purchaseDetail.setAmount(bizPurchase.getDetailList().get(i).getTotalAmount());
                res = bizPurchaseDetailService.save(purchaseDetail);

                String productCode = purchaseDetail.getProductCode();
                BizProduct bizProduct = bizProductService.getBizProductByProductCode(productCode);
                if (StringUtil.isNotEmpty(bizProduct.getInventoryFlag())) {
                    if ("0".equals(bizProduct.getInventoryFlag())) {
                        if (purchaseDetail.getTotalAmount() != null) {
                            amount = amount.add(purchaseDetail.getTotalAmount());
                        }
                    }
                }
            }
            if (amount.compareTo(BigDecimal.ZERO)>0){
               updatePurchaseDetail(bizPurchase.getPurchaseCode(),amount);
            }
        }
        return res;
    }

    @Transactional(rollbackFor = Exception.class)
    public void updatePurchaseDetail(String purchaseCode,BigDecimal amount) {
        BizPurchaseDetail bizPurchaseDetail= new BizPurchaseDetail();
        bizPurchaseDetail.setPurchaseCode(purchaseCode);
        bizPurchaseDetail.setInventoryFlag("1");
        List<BizPurchaseDetail> bizPurchaseDetailList = bizPurchaseDetailService.findList(bizPurchaseDetail);
        if (bizPurchaseDetailList !=null && bizPurchaseDetailList.size()>0){
            int size = bizPurchaseDetailList.size();
            BigDecimal averagePrice = amount.divide(BigDecimal.valueOf(size),2, RoundingMode.HALF_UP);
            for (BizPurchaseDetail purchaseDetail : bizPurchaseDetailList) {
                BigDecimal totalAmount = purchaseDetail.getTotalAmount();
                if (totalAmount !=null){
                    BigDecimal addTotalAmount = totalAmount.add(averagePrice);
                    if (purchaseDetail.getProductNumber() != null && purchaseDetail.getProductNumber().compareTo(BigDecimal.ZERO)>0) {
                        BigDecimal unitPrice = addTotalAmount.divide(purchaseDetail.getProductNumber(), 2, RoundingMode.HALF_UP);
                        purchaseDetail.setBalance(unitPrice);
                        purchaseDetail.setAmount(addTotalAmount);
                        bizPurchaseDetailService.save(purchaseDetail);
                    }
                }
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updatePurchase(BizPurchase bizPurchase) {
        BigDecimal purchaseAmount = BigDecimal.ZERO;
        if(bizPurchase.getDetailList().size() > 0) {
            for (int i = 0; i < bizPurchase.getDetailList().size(); i++) {
                if(null == bizPurchase.getDetailList().get(i).getProductNumber() || bizPurchase.getDetailList().get(i).getProductNumber().compareTo(BigDecimal.ZERO) == 0){
                    throw new BizException("明细数量必须大于0！");
                }
//                if(null == bizPurchase.getDetailList().get(i).getTotalAmount() || bizPurchase.getDetailList().get(i).getTotalAmount().compareTo(BigDecimal.ZERO) == 0){
//                    throw new BizException("明细金额必须大于0！");
//                }
            }
            purchaseAmount = bizPurchase.getDetailList().stream().map(BizPurchaseDetail::getTotalAmount).reduce(BigDecimal.ZERO,BigDecimal::add);
        }
        bizPurchase.setPurchaseAmount(purchaseAmount);
        boolean update = super.save(bizPurchase);
        if(update) {
            Set<String> existsSets = Sets.newHashSet();
            List<BizPurchaseDetail> bizPurchaseDetailList = bizPurchaseDetailService.getBizPurchaseDetailByPurchaseCode(bizPurchase.getPurchaseCode());
            if (bizPurchaseDetailList !=null && bizPurchaseDetailList.size()>0){
                bizPurchaseDetailList.forEach(existsVO -> {
                    existsSets.add(existsVO.getId());
                });
            }
            List<BizPurchaseDetail> detailList = bizPurchase.getDetailList();
            if (detailList != null && detailList.size() > 0) {
                BigDecimal amount = BigDecimal.ZERO;
                for (BizPurchaseDetail bizPurchaseDetail : detailList) {
                    bizPurchaseDetail.setSupplierCode(bizPurchase.getSupplierCode());
                    bizPurchaseDetail.setPurchaseCode(bizPurchase.getPurchaseCode());
                    bizPurchaseDetail.setTenantId(bizPurchase.getTenantId());
                    bizPurchaseDetail.setBalance(bizPurchaseDetail.getUnitPrice());
                    bizPurchaseDetail.setAmount(bizPurchaseDetail.getTotalAmount());
                    existsSets.remove(bizPurchaseDetail.getId());
                    bizPurchaseDetailService.save(bizPurchaseDetail);

                    String productCode = bizPurchaseDetail.getProductCode();
                    BizProduct bizProduct = bizProductService.getBizProductByProductCode(productCode);
                    if (StringUtil.isNotEmpty(bizProduct.getInventoryFlag())) {
                        if ("0".equals(bizProduct.getInventoryFlag())) {
                            if (bizPurchaseDetail.getTotalAmount() != null) {
                                amount = amount.add(bizPurchaseDetail.getTotalAmount());
                            }
                        }
                    }
                }
                if (amount.compareTo(BigDecimal.ZERO)>0){
                    updatePurchaseDetail(bizPurchase.getPurchaseCode(),amount);
                }
            }
            if (existsSets.size()>0){
                String[] ids = existsSets.toArray(new String[0]);
                bizPurchaseDetailService.deleteBizPurchaseDetailByIds(ids, BaseEntity.DEL_FLAG_DELETE);
            }

            return true;
        }

        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditPurchase(String id) {
        BizPurchase bizPurchase = super.get(id.split(":")[0]);
        bizPurchase.setStatus(Integer.parseInt(id.split(":")[1]));
        int update = bizPurchaseMapper.update(bizPurchase);
        if(update > 0) {
            if (bizPurchase.getStatus().equals(2)) {
                BizSupplierPayable supplierPayable = bizSupplierPayableMapper.getBizSupplierPayableBySupplierCode(bizPurchase.getSupplierCode());
                if (null == supplierPayable) {
                    supplierPayable = new BizSupplierPayable();
                    supplierPayable.preInsert();
                    supplierPayable.setTotalAmount(bizPurchase.getPurchaseAmount());
                    supplierPayable.setHasAmount(bizPurchase.getPurchaseAmount());
                    supplierPayable.setPayAmount(BigDecimal.ZERO);
                    supplierPayable.setAdvanceAmount(BigDecimal.ZERO);
                    supplierPayable.setSupplierCode(bizPurchase.getSupplierCode());
                    supplierPayable.setTenantId(bizPurchase.getTenantId());
                    BizSupplier supplier = bizSupplierMapper.getBizSupplierBySupplierCode(bizPurchase.getSupplierCode());
                    supplierPayable.setSupplierName(supplier.getSupplierName());
                    bizSupplierPayableMapper.insert(supplierPayable);
                } else {
                    supplierPayable.setTotalAmount(supplierPayable.getTotalAmount().add(bizPurchase.getPurchaseAmount()));
                    supplierPayable.setHasAmount(supplierPayable.getHasAmount().add(bizPurchase.getPurchaseAmount()));
                    bizSupplierPayableMapper.update(supplierPayable);
                }
                //查询采购单明细信息
                BizPurchaseDetail paramDetail = new BizPurchaseDetail();
                paramDetail.setPurchaseCode(bizPurchase.getPurchaseCode());
                List<BizPurchaseDetail> bizPurchaseDetails = bizPurchaseDetailService.findList(paramDetail);
                for (BizPurchaseDetail bizPurchaseDetail : bizPurchaseDetails) {
                    if (StringUtils.isEmpty(bizPurchaseDetail.getSpaceId())){
                        throw new BizException("审核通过时，明细库位不能为空");
                    }
                    BizProduct bizProduct = bizProductService.getBizProductByProductCode(bizPurchaseDetail.getProductCode());
                    //计算基础数量
                    BigDecimal basicNumber = ConvertRatioNumberUnit.convertRatio(bizPurchaseDetail.getProductNumber(), bizPurchaseDetail.getUnit(), bizProduct);
                    if (bizProduct.getInventoryFlag()!=null && "1".equals(bizProduct.getInventoryFlag())){
                        BizProductInventory bizProductInventory = bizProductInventoryService.getByProductIdAndSpaceId(bizProduct.getId(),bizPurchaseDetail.getSpaceId());
                        if (bizProductInventory == null) {
                            bizProductInventory = new BizProductInventory();
                            BeanUtil.copyProperties(bizPurchaseDetail, bizProductInventory);
                            bizProductInventory.setProductId(bizProduct.getId());
                            bizProductInventory.setAmount(bizPurchaseDetail.getAmount());
                            bizProductInventory.setNumber(basicNumber);
                            bizProductInventory.setPrice(bizPurchaseDetail.getBalance());
                            bizProductInventory.setTenantId(SecurityUtils.getTenantId());
                            bizProductInventory.setWarehouseId(bizPurchase.getWarehouseId());
                            bizProductInventory.setId(null);
                            bizProductInventory.setAssistNumberA(bizProductInventory.getNumber().multiply(bizProduct.getConvertRatioA()).setScale(3, BigDecimal.ROUND_HALF_UP));
                            bizProductInventory.setAssistNumberB(bizProductInventory.getNumber().multiply(bizProduct.getConvertRatioB()).setScale(3, BigDecimal.ROUND_HALF_UP));
                            bizProductInventoryService.save(bizProductInventory);
                        } else {
                            bizProductInventory.setProductId(bizProduct.getId());
                            BigDecimal number = bizProductInventory.getNumber() == null ? BigDecimal.ZERO : bizProductInventory.getNumber();
                            BigDecimal productNumber = number.add(basicNumber);
                            BigDecimal amount = bizProductInventory.getAmount()  == null ? BigDecimal.ZERO : bizProductInventory.getAmount();
                            BigDecimal totalAmount = amount.add(bizPurchaseDetail.getAmount());
                            bizProductInventory.setAmount(totalAmount);
                            if (totalAmount.compareTo(BigDecimal.ZERO)>0 && productNumber.compareTo(BigDecimal.ZERO)>0){
                                bizProductInventory.setPrice(totalAmount.divide(productNumber,3,BigDecimal.ROUND_HALF_UP));
                            }else {
                                bizProductInventory.setPrice(BigDecimal.ZERO);
                            }
//                        bizProductInventory.setAmount(bizProductInventory.getAmount().add(bizPurchaseDetail.getTotalAmount()));
                            bizProductInventory.setNumber(bizProductInventory.getNumber().add(basicNumber));
//                        bizProductInventory.setPrice(bizProductInventory.getAmount().divide(bizProductInventory.getNumber()).setScale(2, BigDecimal.ROUND_HALF_UP));
                            bizProductInventory.setAssistNumberA(bizProductInventory.getNumber().multiply(bizProduct.getConvertRatioA()).setScale(3, BigDecimal.ROUND_HALF_UP));
                            bizProductInventory.setAssistNumberB(bizProductInventory.getNumber().multiply(bizProduct.getConvertRatioB()).setScale(3, BigDecimal.ROUND_HALF_UP));
                            bizProductInventoryService.update(bizProductInventory);
                        }
                        //保存产品库存台账
                        BizProductInventoryBook productInventoryBook = new BizProductInventoryBook();
                        productInventoryBook.setBizDate(DateUtils.getNowDate());
                        productInventoryBook.setAmount(bizPurchaseDetail.getAmount());
                        productInventoryBook.setAssistUnitA(bizProductInventory.getAssistUnitA());
                        productInventoryBook.setAssistUnitB(bizProductInventory.getAssistUnitB());
                        productInventoryBook.setInventoryId(bizProductInventory.getId());
                        productInventoryBook.setNumber(basicNumber);
                        productInventoryBook.setAssistNumberB(basicNumber.multiply(bizProduct.getConvertRatioB()).setScale(3, BigDecimal.ROUND_HALF_UP));
                        productInventoryBook.setAssistNumberA(basicNumber.multiply(bizProduct.getConvertRatioA()).setScale(3, BigDecimal.ROUND_HALF_UP));
                        productInventoryBook.setOrderNumber(bizPurchase.getPurchaseCode());
                        productInventoryBook.setOrderType(BizConstants.ORDER_TYPE_PURCHASE);
                        productInventoryBook.setPrice(bizPurchaseDetail.getBalance());
                        productInventoryBook.setProductModel(bizPurchaseDetail.getProductModel());
                        productInventoryBook.setTenantId(SecurityUtils.getTenantId());
                        productInventoryBook.setWarehouseId(bizPurchase.getWarehouseId());
                        productInventoryBook.setSpaceId(bizPurchaseDetail.getSpaceId());
                        productInventoryBook.setProductId(bizProduct.getId());
                        productInventoryBook.setCustomer(bizPurchase.getSupplierCode());
                        productInventoryBook.setRemark(bizPurchaseDetail.getRemark());
                        productInventoryBook.setOrderType("2");
                        bizProductInventoryBookService.save(productInventoryBook);
                    }
                }
                return true;
            } else if (bizPurchase.getStatus().equals(1)) {
                //反审
                BizSupplierPayable supplierPayable = bizSupplierPayableMapper.getBizSupplierPayableBySupplierCode(bizPurchase.getSupplierCode());
                supplierPayable.setTotalAmount(supplierPayable.getTotalAmount().subtract(bizPurchase.getPurchaseAmount()));
                supplierPayable.setHasAmount(supplierPayable.getHasAmount().subtract(bizPurchase.getPurchaseAmount()));
                bizSupplierPayableMapper.update(supplierPayable);

                //查询采购单明细信息
                BizPurchaseDetail paramDetail = new BizPurchaseDetail();
                paramDetail.setPurchaseCode(bizPurchase.getPurchaseCode());
                List<BizPurchaseDetail> bizPurchaseDetails = bizPurchaseDetailService.findList(paramDetail);
                for (BizPurchaseDetail bizPurchaseDetail : bizPurchaseDetails) {
                    BizProduct bizProduct = bizProductService.getBizProductByProductCode(bizPurchaseDetail.getProductCode());
                    if (bizProduct.getInventoryFlag()!=null && "1".equals(bizProduct.getInventoryFlag())){
                        BizProductInventory bizProductInventory = bizProductInventoryService.getByProductIdAndSpaceId(bizProduct.getId(), bizPurchaseDetail.getSpaceId());
                        //计算基础数量
                        BigDecimal basicNumber = ConvertRatioNumberUnit.convertRatio(bizPurchaseDetail.getProductNumber(), bizPurchaseDetail.getUnit(), bizProduct);
                        if(bizProductInventory!=null) {
                            BigDecimal number = bizProductInventory.getNumber() == null ? BigDecimal.ZERO : bizProductInventory.getNumber();
                            BigDecimal productNumber = number.add(basicNumber);
                            BigDecimal amount = bizProductInventory.getAmount()  == null ? BigDecimal.ZERO : bizProductInventory.getAmount();
                            BigDecimal totalAmount = amount.add(bizPurchaseDetail.getTotalAmount());
                            bizProductInventory.setAmount(totalAmount);
                            if (totalAmount.compareTo(BigDecimal.ZERO)>0){
                                bizProductInventory.setPrice(totalAmount.divide(productNumber,3,BigDecimal.ROUND_HALF_UP));
                            }else {
                                bizProductInventory.setPrice(BigDecimal.ZERO);
                            }
//                        bizProductInventory.setAmount(bizProductInventory.getAmount().subtract(bizPurchaseDetail.getTotalAmount()));
                            bizProductInventory.setNumber(bizProductInventory.getNumber().subtract(basicNumber));
//                        if(BigDecimal.ZERO.compareTo(bizProductInventory.getNumber())!=0) {
//                            bizProductInventory.setPrice(bizProductInventory.getAmount().divide(bizProductInventory.getNumber()).setScale(2, BigDecimal.ROUND_HALF_UP));
//                        }
                            bizProductInventory.setAssistNumberA(bizProductInventory.getNumber().multiply(bizProduct.getConvertRatioA()).setScale(3, BigDecimal.ROUND_HALF_UP));
                            bizProductInventory.setAssistNumberB(bizProductInventory.getNumber().multiply(bizProduct.getConvertRatioB()).setScale(3, BigDecimal.ROUND_HALF_UP));
                            bizProductInventoryService.update(bizProductInventory);

                            //删除台账
                            bizProductInventoryBookService.deleteBizProductInventoryBookByOrderNumber(bizPurchase.getPurchaseCode());
                    }
                    }
                }

                return true;
            }
        }
        return false;
    }

    @Override
    public PageInfo<PurchaseProductVo> listPurchaseStatPage(BizPurchase bizPurchase) {
        PageDomain page = bizPurchase.getPage();
        Integer pageNum = page.getPageNum();
        Integer pageSize = page.getPageSize();
        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
        {
            String orderBy = SqlUtil.escapeOrderBySql(page.getOrderBy());
            Boolean reasonable = page.getReasonable();
            PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
        }
        bizPurchase.setTenantId(SecurityUtils.getTenantId());
        return new PageInfo(bizPurchaseMapper.listPurchaseStat(bizPurchase));
    }

    @Override
    public List<PurchaseProductVo> listPurchaseStat(BizPurchase bizPurchase) {
        bizPurchase.setTenantId(SecurityUtils.getTenantId());
        return bizPurchaseMapper.listPurchaseStat(bizPurchase);
    }

}
